# coding: utf-8
# 非阻塞


import time
import socket
import sys


def doRequest():
    sock = socket.socket()
    # 非阻塞的设置
    sock.setblocking(False)
    try:
        sock.connect(("www.baidu.com", 80))
    except BlockingIOError:
        pass
    # 因为设置为非阻塞吗模式，不知道什么时候socket就绪，需要不停的监控socket的状态
    while True:
        try:
            sock.send("GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: Close\r\n\r\n".encode("utf-8"))
            # 直到send 不抛出异常，就发送成功了
            break
        except OSError:
            pass
    while True:
        try:
            response = sock.recv(1024)
            break
        except OSError:
            pass
    return response


def main():
    start = time.time()
    for i in range(int(sys.argv[1])):
        doRequest()
    print("spend time : %s" % (time.time() - start))


if __name__ == "__main__":
    main()

"""
>>> python non_blocking.py 10
spend time : 0.6620018482208252

>>> python non_blocking.py 100
spend time : 6.085986375808716

sock.setblocking(False)把socket设置为非阻塞式的，
也就是说执行完sock.connect()和sock.recv()之后， CPU就不会再等待IO了，会继续的往下执行。

因为把socket设置为非阻塞模式了，所以CPU并不知道IO什么时候就绪，所以必须在这里不停的尝试，直到IO可以使用了为止。

虽然 connect() 和 recv() 不再阻塞主程序，空出来的时间段CPU没有空闲着，但并没有利用好这空闲去做其他有意义的事情，而是在循环尝试读写 socket （不停判断非阻塞调用的状态是否就绪）。

有没有办法让CPU空闲出来的时间，不用来不停的询问IO，而是干别的更有意义的事情呢，等IO就绪后再通知CPU回来处理呢？当然有了，那就是回调。

0x04 改进3-回调
操作系统已经把IO状态的改变封装成了事件，如可读事件、可写事件。并且可以为这些事件绑定处理函数。所以我们可以使用这种方式，为socket的IO状态的变化绑定处理函数，交给系统进行调动，这样就是回调方式。python的select模块支持这样的操作。
"""





